package jers.util.daemon;

import java.rmi.activation.ActivationGroup;
import java.rmi.activation.ActivationSystem;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import jers.JERS;
import jers.util.Daemon;
import jers.util.SecurityUtil;
import jers.util.Utility;

/**
 * Classe responsavel por implementar o {@link Demon} do rmid no sistema. 
 */
public class RMIDDaemon implements Daemon {

	/**
	 * Portas usadas pelas instancias do daemon rmid.
	 */
	protected final static Set<Integer> portsUseds;
	static {
		portsUseds = Collections.synchronizedSet(new HashSet<Integer>());
	}
	
	/**
	 * Configura o gerenciador de seguranca do sistema com o decorador
	 * {@link ExitForbiddenSecurityManager}.
	 */
	private void setupSecurityManagerDecorator() {
		SecurityManager system = System.getSecurityManager();
		
		if (!(system instanceof ExitForbiddenSecurityManager)) {
			System.setSecurityManager(new ExitForbiddenSecurityManager(system));	
		}
	}

	/**
	 * Para o daemon rmid que esteja rodando na porta passada.
	 */
	public synchronized void stop(final int port) {
		JERS.log.info("[RMID] stopping rmid daemon on port [", port, "]");
	    try {
			AccessController.doPrivileged(new PrivilegedAction<Void>() {
				public Void run() {
					System.setProperty("java.rmi.activation.port",
							Integer.toString(port));
					return null;
				}
			});
			ActivationSystem system = ActivationGroup.getSystem();
			system.shutdown();
			portsUseds.remove(port);
			
	    } catch (ExitForbiddenException e) {
	    	JERS.log.error("[RMID] Attempt exit forbidden: ",
	    			e.getMessage());
	    } catch (Exception e) {
			JERS.log.error("[RMID] Was not found another service running: ", 
					e.getMessage());
	    }
	    JERS.log.info("[RMID] rmid daemon stopped with success!");
	}

	public void stop() {
		stop(JERS.ACTIVATION_PORT);
	}

	/**
	 * Inicia o daemon rmid na porta passada. 
	 */
	public void start(final int port) {
		JERS.log.info("[RMID] starting rmid daemon on port [", port, "]");
		try {
			if (!portsUseds.contains(port)) {
				portsUseds.add(port);

				stop(port);
				SecurityUtil.setupSecurityPolicy();
				setupSecurityManagerDecorator();
				
				Thread thread = new Thread() {
					@Override
					@SuppressWarnings("restriction")
					public void run() {
						try {
							sun.rmi.server.Activation.main(new String[] {
									"-port", Utility.concat(port)
							});
						} catch (Exception e) {
							JERS.log.error("[RMID] Error on run ",
									"Activation.main(-port ", port, ")");
						}
					}
				};
				thread.setPriority(Thread.MAX_PRIORITY);
				thread.start();
				Thread.yield();
			}
		} catch (ExitForbiddenException e) {
	    	JERS.log.error("[RMID] Attempt exit forbidden: ",
	    			e.getMessage());
	    } catch (Exception e) {
	    	JERS.log.error("[RMID] Was not found another service running: ", 
					e.getMessage());
	    }
	    JERS.log.info("[RMID] rmid daemon started with success!");
	}

	public void start() {
		start(JERS.ACTIVATION_PORT);
	}

	public boolean isStarted(int port) {
		return portsUseds.contains(port);
	}
	
	public boolean isStarted() {
		return isStarted(JERS.ACTIVATION_PORT);
	}

	public boolean isStopped(int port) {
		return !portsUseds.contains(port);
	}
	
	public boolean isStopped() {
		return isStopped(JERS.ACTIVATION_PORT);
	}
	
}